package com.ocm.core.associationType.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Property;
import javax.jcr.Session;
import javax.jcr.Value;

import org.apache.jackrabbit.JcrConstants;

import com.ocm.core.constant.OCMConstant;
import com.ocm.core.domain.ClassDefinition;
import com.ocm.core.domain.PropertyDefinition;
import com.ocm.core.domain.PropertyType;
import com.ocm.core.exception.OCMException;
import com.ocm.core.model.ClassInstance;
import com.ocm.core.model.ReferenceValue;
import com.ocm.core.service.AssociationTypeService;
import com.ocm.core.service.JCRService;

public class OneToMultipleDescOrderationServiceImpl implements AssociationTypeService {

   private JCRService jcrService;

   public Object getPropertyValue(Property property) throws OCMException {
      try{
         String result="";
         Node referenceNode = property.getNode();
         NodeIterator nodes = referenceNode.getNodes();
         while(nodes.hasNext()){
            Node currentNode = nodes.nextNode();
            result += currentNode.getIdentifier() + ",";
         }
         return result;
      }catch (Exception exception){
         throw new OCMException(exception);
      }
   }


   public Object getPropertyObject(Property property) throws OCMException {
      try{
         Node referenceNode = property.getNode();
         NodeIterator nodes = referenceNode.getNodes();
         Value[] result = new Value[(int)nodes.getSize()];
         int index=0;
         while(nodes.hasNext()){
            Node relationNode = nodes.nextNode();
            Node associationNode = relationNode.getProperty(OCMConstant.SYSTEM_RELATED_PROPERTY).getNode();
            result[index++]= PropertyType.OBJECT.convertValue(associationNode);
         }
         return result;
      }catch (Exception exception){
         throw new OCMException(exception);
      }
   }

   public void processReferenceValue(Node instanceClass, String propertyName, ReferenceValue referenceValue)
         throws OCMException {
      try{
         Session session = instanceClass.getSession();
         Node referenceNode = null;
         if (instanceClass.hasProperty(propertyName)) {
            referenceNode = instanceClass.getProperty(propertyName).getNode();
         } else {
            referenceNode = jcrService.addNode(session, instanceClass.getIdentifier(), propertyName, null);
            referenceNode.setProperty(JcrConstants.JCR_HASORDERABLECHILDNODES, true);
            instanceClass.setProperty(propertyName, referenceNode);
         }
         Node relationNode = jcrService.getNodeId(session, referenceValue.getUUID(0));
         Map<String, Object> propertyValues = new HashMap<String, Object>();
         propertyValues.put(OCMConstant.SYSTEM_RELATED_PROPERTY, PropertyType.OBJECT.convertValue(relationNode));
         Node elementNode = jcrService.addNode(session, referenceNode.getIdentifier(), relationNode.getName(), propertyValues);

         NodeIterator nodes = referenceNode.getNodes();
         Node firstNode = nodes.getSize() == 0 ? null : nodes.nextNode();
         if (firstNode != null)
            referenceNode.orderBefore(elementNode.getName(), firstNode.getName());
      }catch (Exception exception){
         throw new OCMException(exception);
      }
   }

   public void setJCRService(JCRService jcrService) {
      this.jcrService = jcrService;
   }


   public Object processClassInstance(Session session, Object propertyValue, long classDef,
         List<PropertyDefinition> filterProperties, int maxItems) throws OCMException {
      try{
         List<ClassInstance> classInstances = new ArrayList<ClassInstance>();
         if (propertyValue != null) {
            Value[] values = (Value[]) propertyValue;
            int length = (0==maxItems?values.length:(values.length<maxItems ? values.length : maxItems));
            for (int index = 0; index < length; index++) {
               Value value = (Value) values[index];
               Node nextNode = this.jcrService.getNodeId(session, value.getString());
               Map<PropertyDefinition, Object> propertyValues = this.jcrService.getValues(nextNode,
                     filterProperties);
               ClassInstance classInstance = new ClassInstance();
               ClassDefinition classDefinition = new ClassDefinition();
               classDefinition.setId(classDef);
               classInstance.setClassDefinition(classDefinition);
               classInstance.setProperties(propertyValues);
               classInstance.setNodeUUID(nextNode.getIdentifier());
               classInstance.setNodeName(nextNode.getName());
               classInstance.setRealPath(nextNode.getPath());
               classInstances.add(classInstance);
            }
         }
         return classInstances;
      }catch (Exception exception){
         throw new OCMException(exception);
      }
   }

   public boolean support(Property property) throws OCMException {
      try{
         if (property.isMultiple() == false && property.getNode() != null && OCMConstant.SYSTEM_RELATED_PROPERTY.equalsIgnoreCase(property.getName()))
            return true; 
         return false;
      }catch (Exception exception){
         throw new OCMException(exception);
      }
   }

   public void removeReference(Property property, Node removeNode) throws OCMException {
      try{
         Node existNode = property.getParent();
         existNode.remove();
      }catch (Exception exception){
         throw new OCMException(exception);
      }
   }
}
